﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Windows.Input;
using Peter.Common;
using Peter.Common.MainMenu;
using Peter.Sdw.Data;
using Peter.Sdw.Properties;

namespace Peter.Sdw.Logic
{
   /// <summary>
   /// View model for a chapter.
   /// </summary>
   public class ChapterModel : BaseModel
   {
      private bool m_Hide;
      private int m_Order;
      private int m_Number;
      private string m_Name;
      private string m_Mode;
      private string m_Header;
      private string m_Footer;
      private RelayCommand m_CmdAddPassages;
      private PassageModel m_SelectedPassage;
      private readonly ObservableCollection<string> m_ReadingModes;
      private readonly ObservableCollection<PassageModel> m_Passages;

      /// <summary>
      /// Initializes a new chapter model.
      /// </summary>
      public ChapterModel (SubBookModel subBook)
         : base (subBook)
      {
         this.SubBook = subBook;
         WebQueue.Instance.WebGetComplete += this.OnGetCompleted;
         WebQueue.Instance.WebPostComplete += this.OnPostCompleted;
         this.m_Passages = new ObservableCollection<PassageModel> ();
         this.m_ReadingModes = new ObservableCollection<string> { Constants.VERSE, Constants.PARAGRAPH };
      }

      /// <summary>
      /// Gets the parent version.
      /// </summary>
      public SubBookModel SubBook { get; private set; }

      #region Chapter Data

      /// <summary>
      /// Gets or Sets the chapter id.
      /// </summary>
      public int ChapterId { get; set; }

      /// <summary>
      /// Gets or Sets the name.
      /// </summary>
      public string Name
      {
         get { return this.m_Name; }
         set
         {
            if (this.m_Name != value) {
               this.m_Name = value;
               this.RaisePropertyChanged ("Name");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the header.
      /// </summary>
      public string Header
      {
         get { return this.m_Header; }
         set
         {
            if (this.m_Header != value) {
               this.m_Header = value;
               this.RaisePropertyChanged ("Header");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the footer.
      /// </summary>
      public string Footer
      {
         get { return this.m_Footer; }
         set
         {
            if (this.m_Footer != value) {
               this.m_Footer = value;
               this.RaisePropertyChanged ("Footer");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the order.
      /// </summary>
      public int Order
      {
         get { return this.m_Order; }
         set
         {
            if (this.m_Order != value) {
               this.m_Order = value;
               this.RaisePropertyChanged ("Order");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the number.
      /// </summary>
      public int Number
      {
         get { return this.m_Number; }
         set
         {
            if (this.m_Number != value) {
               this.m_Number = value;
               this.RaisePropertyChanged ("Number");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets if this should be hidden or not.
      /// </summary>
      public bool Hide
      {
         get { return this.m_Hide; }
         set
         {
            if (this.m_Hide != value) {
               this.m_Hide = value;
               this.RaisePropertyChanged ("Hide");
               this.Edit ();
            }
         }
      }

      /// <summary>
      /// Gets or Sets the reading mode.
      /// </summary>
      public string Mode
      {
         get { return this.m_Mode; }
         set
         {
            if (this.m_Mode != value) {
               this.m_Mode = value;
               this.RaisePropertyChanged ("Mode");
               this.Edit ();
            }
         }
      }

      #endregion

      /// <summary>
      /// Gets the list of passages.
      /// </summary>
      public ObservableCollection<PassageModel> Passages { get { return this.m_Passages; } }

      /// <summary>
      /// Gets the list of reading modes.
      /// </summary>
      public ObservableCollection<string> ReadingModes { get { return this.m_ReadingModes; } }

      /// <summary>
      /// Gets the command used to add passages.
      /// </summary>
      public ICommand AddPassagesCommand
      {
         get { return this.m_CmdAddPassages ?? (this.m_CmdAddPassages = new RelayCommand (this.OnAddPassages)); }
      }

      /// <summary>
      /// Gets or Sets the selected passage.
      /// </summary>
      public PassageModel SelectedPassage
      {
         get { return this.m_SelectedPassage; }
         set
         {
            this.m_SelectedPassage = value;
            this.RaisePropertyChanged ("SelectedPassage");
         }
      }

      /// <summary>
      /// Gets the list of passages.
      /// </summary>
      public void GetPassages ()
      {
         this.IsLoading = true;
         this.Passages.Clear ();
         WebQueue.Instance.Get (string.Format (Constants.URL_PASSAGE_LIST, this.Id));
      }

      /// <summary>
      /// Posts edit data to the server.
      /// </summary>
      private void Edit ()
      {
         if (!OkToUpdate) return;
         var parameters = new NameValueCollection {
            {Constants.REQUEST_TOKEN, WebQueue.Instance.RequestToken},
            {"id", this.Id.ToString (CultureInfo.InvariantCulture)},
            {"name", this.Name},
            {"order", this.Order.ToString (CultureInfo.InvariantCulture)},
            {"visible", Convert.ToString(!this.Hide)},
            {"para", Convert.ToString(this.Mode == Constants.PARAGRAPH)},
            {"header", this.Header ?? string.Empty},
            {"footer", this.Footer ?? string.Empty}
         };
         WebQueue.Instance.Post (Constants.URL_EDIT_CHAPTER, parameters);
      }

      /// <summary>
      /// Adds the given passages to the current list.
      /// </summary>
      /// <param name="response"></param>
      private void AddPassages (dynamic response)
      {
         foreach (var passage in response.passages) {
            this.Passages.Add (new PassageModel (this) {
               Id = passage.id,
               Text = passage.text,
               Order = passage.order,
               Number = passage.number,
               Header = passage.header,
               PassageId = passage.passageid
            });
         }
      }

      /// <summary>
      /// Executes the add passage command.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnAddPassages (object obj)
      {
         var editor = this.SubBook.Version.Book.Peter.NewFile ();
         editor.Title = "Add Passages";
         editor.Icon = MainMenuIcon.Noteslist;
         var addContent = new EditorEditEntriesModel { Editor = editor };
         editor.RightContent = addContent;
         addContent.AddRequested += this.OnAddPassageList;
      }

      /// <summary>
      /// Posts the passages to the server.
      /// </summary>
      /// <param name="sender">EditorEditEntriesModel</param>
      /// <param name="e">Empty event arguments.</param>
      private void OnAddPassageList (object sender, EventArgs e)
      {
         this.IsLoading = true;
         var addContent = sender as EditorEditEntriesModel;
         if (addContent != null) {
            addContent.AddRequested -= this.OnAddPassageList;
            var list = addContent.Editor.Text;
            var parameters = new NameValueCollection {
               {Constants.REQUEST_TOKEN, WebQueue.Instance.RequestToken},
               {"subBookId", this.SubBook.Id.ToString (CultureInfo.InvariantCulture)},
               {"passageList", list},
            };
            WebQueue.Instance.Post (Constants.URL_CREATE_PASSAGES, parameters);
            this.SubBook.Version.Book.Peter.CloseDocument (addContent.Editor);
            addContent.Editor = null;
         }
      }

      /// <summary>
      /// Checks to see if this item can be deleted or not.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      protected override bool CanDelete (object obj)
      {
         return this.SelectedPassage != null;
      }

      /// <summary>
      /// Occurs when this item is selected.
      /// </summary>
      protected override void OnSelected ()
      {
         this.GetPassages ();
      }

      /// <summary>
      /// Occurs when a web request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnGetCompleted (object sender, WebRequestEventArgs e)
      {
         try {
            if (e.Url == string.Format (Constants.URL_PASSAGE_LIST, this.Id)) {
               if (e.Response.status == Constants.SUCCESS) {
                  this.AddPassages (e.Response);
               }
               this.IsLoading = false;
            }
         } catch (Exception ex) {
            Console.Error.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Occurs when a web post request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnPostCompleted (object sender, WebRequestEventArgs e)
      {
         if (e.Url == Constants.URL_EDIT_CHAPTER) {
            if (e.Response.status == Constants.SUCCESS)
               Console.WriteLine (Resources.Edit_successful);
         } else if (e.Url == Constants.URL_CREATE_PASSAGES) {
            if (e.Response.status == Constants.SUCCESS) {
               Console.WriteLine (Resources.Passages_Created);
               this.GetPassages ();
            }
         }
      }
   }
}
